package cs4game;



import org.lwjgl.Sys;
import boots.boots.*;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.util.glu.GLU;

@SuppressWarnings("unused")
public class MainStage {

	public final int screenWidth = 900, screenHeight = 900;
	public int size = 21;
	private Camera cam;
	private long lastFrame;
	private World world;
	private Player player;
	private boolean qKey, eKey, aKey, sKey, wKey, dKey, escapeKey, spaceKey, lShiftKey;
	public double dir = 0;
	//private float xFacing = 0f, zFacing = -1f;
	
	private boolean prevClickedL = false;
	private boolean prevClickedR = false;
	private boolean prevClickedM = false;
	private boolean prevSpacedPressed = false;
	
	public void init(){
		/*int mazeX = 20;
		int mazeY = 20;
		MazeGen gen = new MazeGen();
		gen.setDimensions(mazeX, mazeY);
		
		gen.randomMaze(0, 0, mazeX-1, mazeY-1);
		
		boolean[][] maze = new boolean[mazeX*2+1][mazeY*2+1];
		for(int x = 0; x<mazeX*2+1; x++){
			for(int y = 0; y<mazeY*2+1; y++){
				maze[x][y] = false;
			}
		}
		for(int x = 0; x<mazeX*2+1; x++){
			maze[x][0] = true;
			maze[x][mazeY*2] = true;
		}
		for(int y = 0; y<mazeY*2+1; y++){
			maze[0][y] = true;
			maze[mazeX*2][y] = true;
		}
		MazeCell[][] mazeCells= gen.getCellArray();
		
		for(int x = 0; x<mazeX; x++){
			for(int y = 0; y<mazeY; y++){
				
				if(mazeCells[x][y].blocked(MazeCell.RIGHT)){
					maze[2*x][2*y+2] = true;
					maze[2*x+1][2*y+2] = true;
					maze[2*x+2][2*y+2] = true;
				}
				if(mazeCells[x][y].blocked(MazeCell.DOWN)){
					maze[2*x+2][2*y] = true;
					maze[2*x+2][2*y+1] = true;
					maze[2*x+2][2*y+2] = true;
				}
			}
		}
		*/
		try{
			Display.setDisplayMode(new DisplayMode(screenWidth, screenHeight)); //Sets size of the screen (like a JFrame)
			Display.create(); //Physically creates the frame
			Display.setTitle("Working Title"); //title shown at top
		}catch(Exception ex){
			ex.printStackTrace();
			System.exit(0);
		}

		getDelta(); // call once before loop to initialise lastFrame
		
		float[] eye = new float[]{0f, 0f, 0f}; //Places the camera at this (arbitrary) point
		float[] center = new float[]{0f, 0f, -1f}; //Focus the camera (in this case, directly behind);
		float[] up = new float[]{0.0f,-1.0f,0.0f}; //Up is directly up
		cam = new Camera(this, eye, center, up);
		//cam.moveForward(0);
		
		world = new World();
		cam.yaw(360);
		cam.up = new float[]{0f, -1f, 0f};
		size = 21;
		cam.centerOn(new Vector3D(-size/2+1.5, -1.4, -size/2+1.5));
		cam.moveForward(1000);
		
		
		//size = 21;
		/*
		for(int x=0; x<mazeX*2+1; x++){
			for(int y=0; y<mazeY*2+1; y++){
				world.addBlock(new Vector3D(x-size/2+0.5, -0.5, y-size/2+0.5), 0x002f3000);
				if(maze[x][y]){
					world.addBlock(new Vector3D(x-size/2+0.5, -1-0.5, y-size/2+0.5), 0x001f3000);
				}
			}
		}*/
		
		boolean boo = false;
		for(int i = 0; i<size; i++){
			for(int j = 0; j< size; j++){
				if(boo){
					world.addBlock(new Vector3D(i-size/2+0.5, -0.5, j-size/2+0.5), 0x002f3000);
				}else{
					world.addBlock(new Vector3D(i-size/2+0.5, -0.5, j-size/2+0.5), 0x001f3000);
				}
				//if(Math.random()>0.75 && (i!=size/2-1 || j!=size/2))
					//world.addBlock(new Point3D(i-size/2+0.5, -1-0.5, j-size/2+0.5), 0x001f3000);
				boo = !boo;
			}
		}
		world.updateAllBlocks();
		player = new Player(new Vector3D(-size/2+1.5, -1.4, -size/2+1.5), world);
		world.addPlayer(player);
		world.addEntity(new Enemy(new Vector3D(-5.5, -1.4, -5.5), world));
		changeCamera();
		//GL11.glEnable(GL11.GL_LIGHT0);
		
				GL11.glEnable(GL11.GL_DEPTH_TEST);
				GL11.glEnable(GL11.GL_TEXTURE_2D); 
				//GL11.glDisable(GL11.GL_BLEND);

				GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_DECAL);
				GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
				GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
				GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
				GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
				GL11.glMatrixMode(GL11.GL_PROJECTION);
				GLU.gluPerspective( /* field of view in degree */ 40.0f,
						/* aspect ratio */ 1.0f,
						/* Z near */ 0.01f, /* Z far */ 100.0f);
		
		GL11.glDisable(GL11.GL_SMOOTH);
		while(!Display.isCloseRequested() && !escapeKey){ //Waits until the [X] button is pressed //&& !escapeKey){

			display(); //Internal function -- draw everything!
			GL11.glFlush(); //Forces OpenGL to run through its drawing buffer immediately
			int delta = getDelta(); //change in time
			readMouse();
			readKeyboard();
			changePlayerVelocity();
			//hud.draw();
			//world.
			world.moveEntities(delta);
			changeCamera();
			Display.sync(60); //Limits framerate to 60FPS
			Display.update(); //Like repaint
			world.updateAllBlocks();
		}
	}

	private void readMouse() {
		boolean b = Mouse.isButtonDown(0);
		if(!player.dead && b /*&& !prevClickedL*/){
			/*float mX = Mouse.getX();
			float mY = Mouse.getY();
			float angle = (float) Math.atan2(mY-screenHeight/2, mX-screenWidth/2);*/
			player.shootBullet((float) /*angle*/(dir*Math.PI/180));
		}
		prevClickedL = b;//THIS IS GUN STUFF FOR LEFT CLICK!!!!
		
		/*boolean b = Mouse.isButtonDown(0);
		if(!player.dead && b && !prevClickedL){
			float mX = Mouse.getX();
			float mY = Mouse.getY();
			double tempDubX = (((player.pos.x*80)+(mX-screenWidth/2))/80.0);
			double tempDubY = (((player.pos.z*80)+(mY-screenHeight/2))/80.0);
			*//*
			 * These Ifs handle if the position that you clicked was next to zero
			 * if it was between 0 and 1 it makes it .5
			 * if it was between 0 and -1 it makes it -.5
			 * if it was 1 or above it drops the decimal and adds .5
			 * if it was below 1 it drops the decimal and adds a negative .5
			 *//*
			if(tempDubX < 0 && tempDubX > -1){
				tempDubX = -.5;
			}else if(tempDubX >= 0 && tempDubX < 1){
				tempDubX = .5;
			}else if(tempDubX >= 1){
				tempDubX = (int)tempDubX;
				tempDubX += .5;
			}else if(tempDubX <= -1){
				tempDubX = (int)tempDubX;
				tempDubX -= .5;
			}
			if(tempDubY < 0 && tempDubY > -1){
				tempDubY = -.5;
			}else if(tempDubY >= 0 && tempDubY < 1){
				tempDubY = .5;
			}else if(tempDubY >= 1){
				tempDubY = (int)tempDubY;
				tempDubY += .5;
			}else if(tempDubY <= -1){
				tempDubY = (int)tempDubY;
				tempDubY -= .5;
			}
			
			if(!world.allBlocks.keySet().contains(new Vector3D(tempDubX, -2.5, tempDubY))){
				world.removeBlock(new Vector3D(tempDubX, -1.5, tempDubY));
				world.indestructibleBs.remove(new Vector3D(tempDubX, -1.5, tempDubY));
			}else{
				world.removeBlock(new Vector3D(tempDubX, -2.5, tempDubY));
				world.indestructibleBs.remove(new Vector3D(tempDubX, -2.5, tempDubY));
			}
			//world.removeBlock(new Vector3D(tempDubX, -1.5, tempDubY));
			//world.addBlock(new Vector3D(tempDubX, -1.5, tempDubY), 0x001f3000);
		}
		prevClickedL = b;*/
		
		boolean bb = Mouse.isButtonDown(1);
		if(!player.dead && bb && !prevClickedR){
			float mX = Mouse.getX();
			float mY = Mouse.getY();
			double tempDubX = (((player.pos.x*80)+(mX-screenWidth/2))/80.0);
			double tempDubY = (((player.pos.z*80)+(mY-screenHeight/2))/80.0);
			/*
			 * These Ifs handle if the position that you clicked was next to zero
			 * if it was between 0 and 1 it makes it .5
			 * if it was between 0 and -1 it makes it -.5
			 * if it was 1 or above it drops the decimal and adds .5
			 * if it was below 1 it drops the decimal and adds a negative .5
			 */
			if(tempDubX < 0 && tempDubX > -1){
				tempDubX = -.5;
			}else if(tempDubX >= 0 && tempDubX < 1){
				tempDubX = .5;
			}else if(tempDubX >= 1){
				tempDubX = (int)tempDubX;
				tempDubX += .5;
			}else if(tempDubX <= -1){
				tempDubX = (int)tempDubX;
				tempDubX -= .5;
			}
			if(tempDubY < 0 && tempDubY > -1){
				tempDubY = -.5;
			}else if(tempDubY >= 0 && tempDubY < 1){
				tempDubY = .5;
			}else if(tempDubY >= 1){
				tempDubY = (int)tempDubY;
				tempDubY += .5;
			}else if(tempDubY <= -1){
				tempDubY = (int)tempDubY;
				tempDubY -= .5;
			}
			
			if(!world.allBlocks.keySet().contains(new Vector3D(tempDubX, -1.5, tempDubY))){
				world.addBlock(new Vector3D(tempDubX, -1.5, tempDubY), 0x001f3000);
				if(lShiftKey){
					
					world.indestructibleBs.add(new Vector3D(tempDubX, -1.5, tempDubY));

				}
			}else{
				world.addBlock(new Vector3D(tempDubX, -2.5, tempDubY), 0x001f3000);
				if(lShiftKey){
					world.indestructibleBs.add(new Vector3D(tempDubX, -2.5, tempDubY));
				}
			}
		}
		prevClickedR = bb;
		boolean bbb = Mouse.isButtonDown(2);
		//System.out.println(bbb);
		if(!player.dead && bbb && !prevClickedM){
			float mX = Mouse.getX();
			float mY = Mouse.getY();
			double tempDubX = (((player.pos.x*80)+(mX-screenWidth/2))/80);
			double tempDubY = (((player.pos.z*80)+(mY-screenHeight/2))/80);
			
			if(tempDubX < 0 && tempDubX > -1){
				tempDubX = -.5;
			}else if(tempDubX >= 0 && tempDubX < 1){
				tempDubX = .5;
			}else if(tempDubX >= 1){
				tempDubX = (int)tempDubX;
				tempDubX += .5;
			}else if(tempDubX <= -1){
				tempDubX = (int)tempDubX;
				tempDubX -= .5;
			}
			if(tempDubY < 0 && tempDubY > -1){
				tempDubY = -.5;
			}else if(tempDubY >= 0 && tempDubY < 1){
				tempDubY = .5;
			}else if(tempDubY >= 1){
				tempDubY = (int)tempDubY;
				tempDubY += .5;
			}else if(tempDubY <= -1){
				tempDubY = (int)tempDubY;
				tempDubY -= .5;
			}
			
			world.addEntity(new Enemy(new Vector3D(tempDubX, -1.5, tempDubY), world));
		}
		prevClickedM = bbb;
	}

	private void changePlayerVelocity() {
		boolean changed = false;
		float xC = 0, zC = 0, yC = 0;
		if(aKey){
			zC-=0.08f;
			changed = true;
		}
		if(dKey){
			zC+=0.08f;
			changed = true;
		}
		if(qKey){
			/*zFacing += 1f;
			cam.eye = new float[](--xFacing0f, -1f, zFacing};
			System.out.println(zFacing);*/
			cam.yaw(2);
			cam.up = new float[]{0f, -1f, 0f};
			//cam.eye = new float[]{0, 0f, 0f};
			
			dir += 2;
			//cam.eye[2] = -3f;
			//cam.roll(180);
		}
		if(eKey){
			/*zFacing -= 1f;
			cam = new Camera(this, new float[]{++xFacing0f, -1f, zFacing},cam.center,cam.up);
			System.out.println(zFacing);*/
			cam.yaw(-2);
			cam.up = new float[]{0f, -1f, 0f};
			//cam.eye = new float[]{0, 0f, 0f};
			
			dir -= 2;
			//cam.eye[2] = -3f;
			//cam.roll(180);
		}
		if(wKey){
			zC+=Math.sin(dir*Math.PI/180.0)*0.08f;
			xC+=Math.cos(dir*Math.PI/180.0)*0.08f;
			changed = true;
		}
		if(sKey){
			zC-=Math.sin(dir*Math.PI/180.0)*0.08f;
			xC-=Math.cos(dir*Math.PI/180.0)*0.08f;
			changed = true;
		}
		if(spaceKey){
			yC -= .25f;
		}
		//yC += .1f;
		
		if(yC == 0){
			player.setVelocity(new float[]{xC, player.velocity[1], zC});
		}else{
			player.setVelocity(new float[]{xC, yC, zC});
		}
	}

	private void readKeyboard() {
		while(Keyboard.next()){
			switch(Keyboard.getEventKey()){
			case Keyboard.KEY_Q:
				if(Keyboard.getEventKeyState())
					qKey = true;
				else
					qKey = false;	
				break;
			case Keyboard.KEY_E:
				if(Keyboard.getEventKeyState())
					eKey = true;
				else
					eKey = false;	
				break;
			case Keyboard.KEY_A:
				if(Keyboard.getEventKeyState())
					aKey = true;
				else
					aKey = false;	
				break;
			
			case Keyboard.KEY_D:
				if(Keyboard.getEventKeyState())
					dKey = true;
				else
					dKey = false;	
				break;
			case Keyboard.KEY_S:
				if(Keyboard.getEventKeyState())
					sKey = true;
				else
					sKey = false;	
				break;
			case Keyboard.KEY_W:
				if(Keyboard.getEventKeyState())
					wKey = true;
				else
					wKey = false;	
				break;
			case Keyboard.KEY_SPACE:
				if(Keyboard.getEventKeyState())
					spaceKey = true;
				else
					spaceKey = false;	
				break;
			case Keyboard.KEY_LSHIFT:
				if(Keyboard.getEventKeyState())
					lShiftKey = true;
				else
					lShiftKey = false;	
				break;
			/*case Keyboard.KEY_UP:
				if(Keyboard.getEventKeyState())
					upKey = true;
				else
					upKey = false;	
				break;
			case Keyboard.KEY_DOWN:
				if(Keyboard.getEventKeyState())
					downKey = true;
				else
					downKey = false;	
				break;
			case Keyboard.KEY_LEFT:
				if(Keyboard.getEventKeyState())
					leftKey = true;
				else
					leftKey = false;	
				break;
			case Keyboard.KEY_RIGHT:
				if(Keyboard.getEventKeyState())
					rightKey = true;
				else
					rightKey = false;	
				break;
			case Keyboard.KEY_MINUS:
				if(Keyboard.getEventKeyState())
					minusKey = true;
				else
					minusKey = false;	
				break;
			case Keyboard.KEY_ADD:
				if(Keyboard.getEventKeyState())
					plusKey = true;
				else
					plusKey = false;	
				break;
			*/
			case Keyboard.KEY_ESCAPE:
				if(Keyboard.getEventKeyState())
					escapeKey = true;
				else
					escapeKey = false;
			}
		}
	}

	/** 
	 * Calculate how many milliseconds have passed 
	 * since last frame.
	 * 
	 * @return milliseconds passed since last frame 
	 */
	public int getDelta() {
		long time = getTime();
		int delta = (int) (time - lastFrame);
		lastFrame = time;

		return delta;
	}

	/**
	 * Get the accurate system time
	 * 
	 * @return The system time in milliseconds
	 */
	public long getTime() {
		return (Sys.getTime() * 1000) / Sys.getTimerResolution();
	}

	public void changeCamera(){
		cam.centerOn(player.getPos());
		cam.change();
	}

	private void display() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); //Clears the screen and depth buffers
		world.drawAll();

	}

	public static void main (String[] args){
		new MainStage().init();
	}
}
